#include <iostream>
#include <string>
#include <cmath>
#include <memory>

using std::cout;
using std::endl;
using std::string;
using std::sqrt;
using std::unique_ptr;

// 运行时多态的要素：
// 1：基类包含虚函数
// 2：派生类覆写虚函数
// 3：创建派生类对象
// 4：基类指针/引用指向派生类
// 5：通过指针/引用调用虚函数


class Figure {
public:
    virtual string getName() const = 0;
    virtual double getArea() const = 0;     // 1：基类包含虚函数
};

class Rectangle : public Figure{
public:
    Rectangle(int length = 0, int width = 0);
    string getName() const override;
    double getArea() const override;    // 2: 派生类覆写虚函数
    
private:
    int _length, _width;
};

Rectangle::Rectangle(int length, int width)
    :_length(length)
    ,_width(width)
{}
string Rectangle::getName() const{
    //cout << "Rectangle";
    return "矩形";
}
double Rectangle::getArea() const{
    //cout << _length * _width;
    return _length * _width;
}

class Circle : public Figure {
public:
    Circle(double radius = 0);
    string getName() const override;
    double getArea() const override;
private:
    double _radius;
};

Circle::Circle(double radius) 
    : _radius(radius) 
{}

string Circle::getName() const {
    return "圆形";
}

double Circle::getArea() const {
    return 3.14159 * _radius * _radius; // πr²
}

class Triangle : public Figure {
public:
    Triangle(double a, double b, double c);
    string getName() const override;
    double getArea() const override;
private:
    double _a, _b, _c;
};

Triangle::Triangle(double a, double b, double c)
    : _a(a), _b(b), _c(c) {}

string Triangle::getName() const {
    return "三角形";
}

double Triangle::getArea() const {
    // 海伦公式计算面积
    double p = (_a + _b + _c) / 2.0;
    double ret = sqrt((double)p * (p * _a) * (p - _b) * (p - _c));
    return ret;
}


void display(Figure & fig) {    // 4：基类引用绑定派生类对象（通过形参绑定对象，调用Rectangle的r等）
    cout << fig.getName()       // 5：通过基类引用调用虚函数（动态绑定）
         << "的面积是:" 
         << fig.getArea() << endl ;
}

void test1() {
    Rectangle r(10, 20);    // 3：创建派生类实例
    Circle c(15);
    Triangle t(3, 4, 5);
    display(r);
    display(c);
    display(t);
}

void test2() {
    Figure* ptr1 = new Rectangle(10, 20);   // 3：创建派生类实例；4：基类指针指向派生类对象
    Figure* ptr2 = new Circle(15);
    unique_ptr<Figure> ptr3 = std::make_unique<Triangle>(3, 4, 5);
    unique_ptr<Figure> ptr4(new Triangle(4, 5, 6));
    cout << ptr1->getName() << endl;        // 5：通过基类引用调用虚函数（动态绑定）
    cout << ptr2->getName() << endl;
    cout << ptr3->getName() << endl;
    cout << ptr4->getName() << endl;
    delete ptr1;
    delete ptr2;
}

int main()
{
    //test1();
    test2();
    return 0;
}

